﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using iPlayMVVM.Model;
using System.Collections.ObjectModel;
using iTunesLib;
using MvvmFoundation.Wpf;
using System.Windows.Input;
using System.Windows;
using System.IO;
using System.Timers;
using System.Diagnostics;
using System.Reflection;
using System.Xml;

namespace iPlayMVVM.ViewModel
{
    class iTunesViewModel : ObservableObject
    {
        #region Locals

        /// <summary>
        /// Global iTunes App to Interface with iTunes
        /// </summary>
        public iTunesApp iTunes = new iTunesApp();

        /// <summary>
        /// Handles the actual generation of the playlist and the post-action
        /// </summary>
        public BackgroundWorker bcLoad = new BackgroundWorker();

        /// <summary>
        /// Handles Checking the current song and playstate from iTunes
        /// Event Handlers SHOULD be used, but due to their poor implementation, this timer is the best option
        /// </summary>
        public Timer Clock;

        /// <summary>
        /// Name of the Last playlist created, used for Refreshing
        /// </summary>
        public string PreviousPlaylist;

        /// <summary>
        /// Keeps track of all artists added. Cleared when refresh is turned off. 
        /// </summary>
        public List<String> ArtistsAdded = new List<String>();

        /// <summary>
        /// Keeps track of all artists added to the current playlist. 
        /// </summary>
        public List<String> ArtistsUsed = new List<String>();

        /// <summary>
        /// Keeps track of the songs added to the current Playlist.
        /// </summary>
        public List<IITTrack> LocalSongsUsed = new List<IITTrack>();

        /// <summary>
        /// This is the list of Valid tracks. It is set to a copy of "Tracks" when appropriate
        /// </summary>
        public List<IITTrack> ValidTracks = new List<IITTrack>();

        /// <summary>
        /// Save Path is the path to the folder to store application data
        /// </summary>
        string SavePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "");

        #endregion

        #region Constructor
        /// <summary>
        /// Constructor - Add's event handlers for background worker and timer and starts the timer
        /// </summary>
        public iTunesViewModel()
        {
            LoadSettings();

            bcLoad.DoWork += new DoWorkEventHandler(bcLoad_DoWork);
            bcLoad.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bcLoad_RunWorkerCompleted);

            Clock = new Timer();
            Clock.Interval = 1000;
            Clock.Start();
            Clock.Elapsed += new ElapsedEventHandler(Check_Song);

            
            bcLoad.WorkerSupportsCancellation = true;

            if(!Directory.Exists(SavePath))
            {
                Directory.CreateDirectory(SavePath);
            }

            //if (QuickGenerate)
            //{
            //    LoadPlaylists();
            //    LoadSongs();
            //    bcLoad.RunWorkerAsync();
            //}
        }


        #endregion

        #region Properties

        #region Current Song and Playback Properties

        private IITTrack _CurrentSong;
        /// <summary>
        /// The Currently Playing Song in iTunes - used to show the NowPlaying tab and FullScreen mode
        /// </summary>
        public Object CurrentSong
        {
            get
            {
                return _CurrentSong;
            }
            set
            {
                _CurrentSong = (IITTrack)value;
                if (CurrentSong != null)
                {
                    IITArtworkCollection Art = ((IITTrack)CurrentSong).Artwork;
                    string extension = "";
                    string savestring = "";
                    try
                    {
                        ClearImgCache();

                        foreach (var art in Art)
                        {
                            if (((IITArtwork)art).Format == ITArtworkFormat.ITArtworkFormatBMP)
                            {
                                extension = ".bmp";
                            }
                            else if (((IITArtwork)art).Format == ITArtworkFormat.ITArtworkFormatJPEG)
                            {
                                extension = ".jpg";
                            }
                            else if (((IITArtwork)art).Format == ITArtworkFormat.ITArtworkFormatPNG)
                            {
                                extension = ".png";
                            }
                            
                            savestring = SavePath + "\\iPlay\\Album" + System.DateTime.Now.Millisecond + extension;
                            ((IITArtwork)art).SaveArtworkToFile(savestring);
                        }
                    }
                    catch
                    {
                        //probably can't over-save the image, so don't - swallow it, clear cache.
                        ClearImgCache();
                    }
                    ArtworkPath = savestring;
                    RaisePropertyChanged("CurrentSong");
                }
            }
        }

        public void ClearImgCache()
        {
            DirectoryInfo di = new DirectoryInfo(SavePath + "\\iPlay");
            List<string> imgFilter = new List<string>(new string[] { "*.jpg", "*.bmp", "*.png" });
            foreach (string filter in imgFilter)
            {
                foreach (FileInfo fi in di.GetFiles(filter))
                {
                    try
                    {
                        fi.Delete();
                    }
                    catch
                    {
                        //EventLog.WriteEntry("iPlay", "Cache cleared, file in use");
                    }
                }
            }
        }

        private String _ArtworkPath;
        /// <summary>
        /// String Path to the artwork of CurrentSong - this is used because the artwork is currently cached to a file, instead of retrieved directly
        /// </summary>
        public String ArtworkPath
        {
            get
            {
                return _ArtworkPath;
            }
            set
            {
                _ArtworkPath = value;
                RaisePropertyChanged("ArtworkPath");
            }
        }

        /// <summary>
        /// The current PlayState of iTunes (play/pause) - used for controls
        /// </summary>
        public bool PlayState
        {
            get
            {
                if (iTunes.PlayerState == ITPlayerState.ITPlayerStatePlaying)
                {
                    return true;
                }
                else if (iTunes.PlayerState == ITPlayerState.ITPlayerStateStopped)
                {
                    return false;
                }
                else
                {
                    return false;
                }
            }
        }

        private int _TrackDuration;
        /// <summary>
        /// The duration (in seconds) of the current song
        /// </summary>
        public int TrackDuration
        {
            get
            {
                return _TrackDuration;
            }
            set
            {
                _TrackDuration = value;
                RaisePropertyChanged("TrackDuration");
            }
        }

        private int _PlayerPosition;
        /// <summary>
        /// The Seconds elapsed in the Current song
        /// </summary>
        public int PlayerPosition
        {
            get
            {
                return _PlayerPosition;
            }
            set
            {
                _PlayerPosition = value;
                RaisePropertyChanged("PlayerPosition");
            }
        }

        #endregion

        private IITPlaylist _SelectedPlaylist;
        /// <summary>
        /// IITPlaylist type - the Selected Source Playlist
        /// </summary>
        public Object SelectedPlaylist
        {
            get
            {
                if (_SelectedPlaylist == null)
                {
                    if (Playlists == null)
                    {
                        LoadPlaylists();
                    }
                    _SelectedPlaylist = (IITPlaylist)iTunes.LibraryPlaylist;
                }
                return _SelectedPlaylist;
            }
            set 
            {
                if (value != null && (_SelectedPlaylist == null || _SelectedPlaylist.playlistID != ((IITPlaylist)value).playlistID))
                {
                    _SelectedPlaylist = (IITPlaylist)value;
                    LoadSongs();
                    RaisePropertyChanged("SelectedPlaylist");
                    if (NumberOfSongs > Tracks.Count)
                    {
                        NumberOfSongs = Tracks.Count;
                    }
                }
            }
        }

        private List<IITPlaylist> _Playlists;
        /// <summary>
        /// Collection of all Playlists from iTunes
        /// </summary>
        public List<IITPlaylist> Playlists
        {
            get
            {
                return _Playlists;
            }
            set
            {
                _Playlists = value;
                RaisePropertyChanged("Playlists");
            }
        }

        private List<IITTrack> _Tracks;
        /// <summary>
        /// The List of tracks in the SelectedPlaylist
        /// Updated when SelectedPlaylist is changed.
        /// </summary>
        public List<IITTrack> Tracks
        {
            get
            {
                return _Tracks;
            }
            set
            {
                _Tracks = value;
                RaisePropertyChanged("Tracks");
            }
        }

        private bool _Substring;
        /// <summary>
        /// Playlist Option to search by substring
        /// True = by Substring || False = by Exact Match
        /// </summary>
        public bool Substring
        {
            get
            {
                return _Substring;
            }
            set
            {
                _Substring = value;
                RaisePropertyChanged("Substring");
            }
        }

        private bool _BlackOrWhiteList;
        /// <summary>
        /// True = "Choose From" || False = "Blacklist"
        /// </summary>
        public bool BlackOrWhiteList
        {
            get
            {
                return _BlackOrWhiteList;
            }
            set
            {
                _BlackOrWhiteList = value;
                RaisePropertyChanged("BlackOrWhiteList");
            }
        }

        private List<String> _BlacklistArtists;
        /// <summary>
        /// List of all Artists typed in by the User
        /// Might be a whitelist or "choose from" list, depending on BlackOrWhiteList
        /// </summary>
        public List<String> BlacklistArtists
        {
            get
            {
                return _BlacklistArtists;
            }
            set
            {
                _BlacklistArtists = value;
                RaisePropertyChanged("BlacklistArtists");
            }
        }

        private int _NumberOfSongs;
        /// <summary>
        /// The number of songs selected by the user for addition to the playlist
        /// </summary>
        public int NumberOfSongs
        {
            get
            {
                return _NumberOfSongs;
            }
            set
            {
                _NumberOfSongs = value;
                RaisePropertyChanged("NumberOfSongs");
            }
        }

        private String _PlaylistName;
        /// <summary>
        /// The Name of the New Playlist
        /// </summary>
        public String PlaylistName
        {
            get
            {
                if (String.IsNullOrEmpty(_PlaylistName))
                {
                    return "iPlayList - " + DateTime.Now.ToShortDateString();
                }
                return _PlaylistName;
            }
            set
            {
                _PlaylistName = value;
                RaisePropertyChanged("PlaylistName");
            }
        }

        private bool _IsIdle = true;
        /// <summary>
        /// Used in the UI to determine visibility states
        /// </summary>
        public bool IsIdle
        {
            get
            {
                return _IsIdle;
            }
            set
            {
                _IsIdle = value;
                RaisePropertyChanged("IsIdle");
            }
        }

        private bool _NoDuplicates;
        /// <summary>
        /// Playlist Option For No Duplicate Artists to be added
        /// </summary>
        public bool NoDuplicates
        {
            get
            {
                return _NoDuplicates;
            }
            set
            {
                _NoDuplicates = value;
                RaisePropertyChanged("NoDuplicates");
            }
        }

        private bool _OverWrite = true;
        /// <summary>
        /// Playlist Option to overwrite an existing playlist of the same name
        /// </summary>
        public bool OverWrite
        {
            get
            {
                return _OverWrite;
            }
            set
            {
                _OverWrite = value;
                RaisePropertyChanged("OverWrite");
            }
        }

        private bool _RefreshSongs;
        /// <summary>
        /// Playlist option to refresh all songs (Do not add any that have been previously added)
        /// </summary>
        public bool RefreshSongs
        {
            get
            {
                return _RefreshSongs;
            }
            set
            {
                _RefreshSongs = value;
                RaisePropertyChanged("RefreshSongs");
            }
        }

        private bool _RefreshArtists;
        /// <summary>
        /// Playlist Option to refresh artists (do not add any that have been previously added)
        /// </summary>
        public bool RefreshArtists
        {
            get
            {
                return _RefreshArtists;
            }
            set
            {
                _RefreshArtists = value;
            }
        }

        private List<IITTrack> _SongsUsed;
        /// <summary>
        /// List of songs that Have been used in the current playlist
        /// </summary>
        public List<IITTrack> SongsUsed
        {
            get
            {
                return _SongsUsed;
            }
            set
            {
                _SongsUsed = value;
                RaisePropertyChanged("SongsUsed");
            }
        }

        private String _ButtonMessage = "Generate";
        /// <summary>
        /// Message to show on the "execute" button
        /// Determines what action to take when the button is clicked.
        /// Consider changing this property to an IEnumerable and using proper converters
        /// </summary>
        public String ButtonMessage
        {
            get
            {
                return _ButtonMessage;
            }
            set
            {
                _ButtonMessage = value;
                RaisePropertyChanged("ButtonMessage");
            }
        }

        private String _GradientColor1;
        public String GradientColor1
        {
            get
            {
                return _GradientColor1;
            }
            set
            {
                _GradientColor1 = value;
                RaisePropertyChanged("GradientColor1");
            }
        }

        private String _GradientColor2;
        public String GradientColor2
        {
            get
            {
                return _GradientColor2;
            }
            set
            {
                _GradientColor2 = value;
                RaisePropertyChanged("GradientColor2");
            }
        }

        private String _AlwaysOnTop;
        public String AlwaysOnTop
        {
            get
            {
                return _AlwaysOnTop;
            }
            set
            {
                _AlwaysOnTop = value;
                RaisePropertyChanged("AlwaysOnTop");
            }
        }

        private bool _SavePlaylistName;
        public bool SavePlaylistName
        {
            get
            {
                return _SavePlaylistName;
            }
            set
            {
                _SavePlaylistName = value;
                RaisePropertyChanged("SavePlaylistName");
            }
        }

        private bool _QuickGenerate;
        public bool QuickGenerate
        {
            get
            {
                return _QuickGenerate;
            }
            set
            {
                _QuickGenerate = value;
                RaisePropertyChanged("QuickGenerate");
            }
        }
       
        #endregion

        #region Commands

        public ICommand LoadPlaylistsCommand
        {
            get
            {
                return new RelayCommand(() => { LoadPlaylists(); });
            }
        }

        public ICommand LoadSongsCommand
        {
            get
            {
                return new RelayCommand(() => { LoadSongs(); });
            }
        }

        public ICommand GeneratePlaylistCommand
        {
            get
            {
                return new RelayCommand(() => { bcLoad.RunWorkerAsync(); });
                //return new RelayCommand(() => { GeneratePlaylist(); });
            }
        }

        public ICommand ExecuteCommand
        {
            get
            {
                return new RelayCommand(() => { Execute(); });
            }
        }

        public ICommand PlayCommand
        {
            get
            {
                return new RelayCommand(() => { iTunes.LibrarySource.Playlists.get_ItemByName(PlaylistName).PlayFirstTrack(); });
            }
        }

        public ICommand FullScreenCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    FullScreen Fs = new FullScreen();
                    Fs.ShowDialog();
                });
            }
        }

        public ICommand SaveSettingsCommand
        { 
            get 
            { 
                return new RelayCommand(() => 
                { 
                    SaveSettings(); 
                });
            }
        }

        public ICommand SaveAppSettingsCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    SaveAppSettings();
                });
            }
        }
        

        #region Now Playing Commands

        public ICommand BackTrack
        {
            get
            {
                return new RelayCommand(() => { 
                    iTunes.BackTrack();
                    CheckSong();
                });
            }
        }

        public ICommand ForwardTrack
        {
            get
            {
                return new RelayCommand(() => { 
                    iTunes.NextTrack();
                    CheckSong();
                });
            }
        }

        public ICommand PlayPause
        {
            get
            {
                return new RelayCommand(() => { 
                    iTunes.PlayPause(); 
                    RaisePropertyChanged("PlayState"); 
                });
            }
        }

        public ICommand NowPlayingCommand
        {
            get
            {
                return new RelayCommand(() => { CurrentSong = iTunes.CurrentTrack; });
            }
        }

        #endregion


        #endregion

        #region Functions

        /// <summary>
        /// Loads the User Settings From the xml file
        /// </summary>
        public void LoadSettings()
        {
            GradientColor1 = Properties.Settings.Default.GradientColor1;
            GradientColor2 = Properties.Settings.Default.GradientColor2;
            PlaylistName = Properties.Settings.Default.PlaylistName;
            AlwaysOnTop = Properties.Settings.Default.AlwaysOnTop;
            SavePlaylistName = Properties.Settings.Default.SavePlaylistName;
            QuickGenerate = Properties.Settings.Default.QuickGenerate;
            NumberOfSongs = Properties.Settings.Default.NumberOfSongs;
            NoDuplicates = Properties.Settings.Default.NoDuplicates;
            if (Properties.Settings.Default.BlacklistArtists == "")
            {
                BlacklistArtists = null;
            }
            else
            {
                BlacklistArtists = new List<string>(Properties.Settings.Default.BlacklistArtists.Split(','));
            }
            OverWrite = Properties.Settings.Default.OverWrite;
            Substring = Properties.Settings.Default.Substring;
            BlackOrWhiteList = Properties.Settings.Default.BlackOrWhiteList;
        }

        /// <summary>
        /// Saves the all user settings to the xml file
        /// </summary>
        public void SaveSettings()
        {
            Properties.Settings.Default.GradientColor1 = GradientColor1;
            Properties.Settings.Default.GradientColor2 = GradientColor2;
            if(SavePlaylistName)
            {
            Properties.Settings.Default.PlaylistName = PlaylistName;
            }else
            {
                Properties.Settings.Default.PlaylistName = "";
            }
            Properties.Settings.Default.AlwaysOnTop = AlwaysOnTop;
            Properties.Settings.Default.SavePlaylistName = SavePlaylistName;
            Properties.Settings.Default.QuickGenerate = QuickGenerate;
            Properties.Settings.Default.NumberOfSongs = NumberOfSongs;
            Properties.Settings.Default.NoDuplicates = NoDuplicates;
            string tmp ="";
            foreach (string t in BlacklistArtists)
            {
                tmp += t;
            }
            tmp = tmp.Trim(',');
            Properties.Settings.Default.BlacklistArtists = tmp;
            Properties.Settings.Default.OverWrite = OverWrite;
            Properties.Settings.Default.Substring = Substring;
            Properties.Settings.Default.BlackOrWhiteList = BlackOrWhiteList;
            Properties.Settings.Default.Save();
        }

        /// <summary>
        /// Saves only the app settings from the tools page
        /// </summary>
        public void SaveAppSettings()
        {
            Properties.Settings.Default.GradientColor1 = GradientColor1;
            Properties.Settings.Default.GradientColor2 = GradientColor2;
            if (SavePlaylistName)
            {
                Properties.Settings.Default.PlaylistName = PlaylistName;
            }
            else
            {
                Properties.Settings.Default.PlaylistName = "";
            }
            Properties.Settings.Default.AlwaysOnTop = AlwaysOnTop;
            Properties.Settings.Default.SavePlaylistName = SavePlaylistName;
            Properties.Settings.Default.QuickGenerate = QuickGenerate;
            if (QuickGenerate)
            {
                Properties.Settings.Default.NumberOfSongs = NumberOfSongs;
            }
            Properties.Settings.Default.Save();

        }

        /// <summary>
        /// Loads all of the tracks from the current SelectedPlaylist
        /// </summary>
        public void LoadSongs()
        {
            List<IITTrack> SongTitles = new List<IITTrack>();

            string playlist = ((IITPlaylist)SelectedPlaylist).Name;
            foreach (IITPlaylist pl in iTunes.LibrarySource.Playlists)
            {
                if (pl.Name == playlist)
                {
                    foreach (IITTrack track in pl.Tracks)
                    {
                        if (!track.Enabled)
                        {
                            continue;
                        }
                        SongTitles.Add(track);
                    }
                    break;
                }
            }
            Tracks = SongTitles;
            ValidTracks = new List<IITTrack>(Tracks);
        }

        /// <summary>
        /// Loads all of the Playlists from iTunes
        /// </summary>
        public void LoadPlaylists()
        {
            List<IITPlaylist> PlaylistCollection = new List<IITPlaylist>();
            
            IITLibraryPlaylist mainLibrary = iTunes.LibraryPlaylist;

            foreach (IITPlaylist pl in iTunes.LibrarySource.Playlists)
            {
                PlaylistCollection.Add(pl);
            }

            Playlists = PlaylistCollection;
            SelectedPlaylist = ((IITPlaylist)iTunes.LibraryPlaylist);
        }

        /// <summary>
        /// Deprecated - Consider Removing
        /// </summary>
        public void GeneratePlaylist()
        {
            bcLoad.RunWorkerAsync();
        }

        /// <summary>
        /// This is the Blood and Guts of the Playlist Generation. See internal comments for help.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void bcLoad_DoWork(object sender, DoWorkEventArgs e)
        {
            //Don't need to check the current song while loading the playlist - the window is locked
            //This is for performance - consider removing based on user preference
            Clock.Stop();

            if (NumberOfSongs == 0)
            {
                e.Cancel = true;
                return;
            }

            //If the source playlist matches the name of the desired playlist exactly, disallow it
            if (iTunes.LibrarySource.Playlists.get_ItemByName(PlaylistName) != null &&
                iTunes.LibrarySource.Playlists.get_ItemByName(PlaylistName).playlistID ==
                iTunes.LibrarySource.Playlists.get_ItemByName(((IITPlaylist)SelectedPlaylist).Name).playlistID)
            {
                MessageBox.Show("Source Playlist Cannot be the same as destination Playlist!", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                e.Cancel = true;
                NumberOfSongs = 0;
                return;
            }

            //Set IsIdle to false and declare a random variable
            IsIdle = false;
            Random rand = new Random();


            //iTunesApp iTunes = new iTunesApp();
            //IITLibraryPlaylist mainLibrary = iTunes.LibraryPlaylist;
            //IITTrackCollection tracks = ((IITPlaylist)SelectedPlaylist).Tracks;
            //List<IITTrack> tracks = new List<IITTrack>(Tracks);
            ////IITSource source = (IITSource)mainLibrary; 
            
            //Get the name of the playlist desired.
            String Name = PlaylistName;
            int instances = 0;
            PreviousPlaylist = Name.Trim().ToUpper();


            //This needs revised a little bit - we don't want to delete *all* playlists that contain the name
            foreach (IITPlaylist pl in iTunes.LibrarySource.Playlists)
            {
                if (bcLoad.CancellationPending == true)
                {
                    e.Cancel = true;
                    return;
                }
                if (pl.Name.Contains(Name))
                {
                    if (_OverWrite)
                    {
                        pl.Delete();
                        break;
                    }
                    else
                    {
                        instances++;
                    }
                }
            }
            if (instances > 0)
            {
                Name = Name + instances.ToString();
            }
            IITPlaylist plist = iTunes.CreatePlaylist(Name);
            IITUserPlaylist PlaylistBeingCreated = (IITUserPlaylist)plist;
            
            //Set the Playlist to Selected in iTunes
            PlaylistBeingCreated.Reveal();

            //GET NEW SONGS!
            if (!RefreshSongs || ValidTracks == null || ValidTracks.Count <= NumberOfSongs || ValidTracks.Count <= 1)
            {
                ValidTracks = new List<IITTrack>(Tracks);
            }
            if (!_RefreshArtists)
            {
                ArtistsAdded = new List<String>();
            }
            else
            {
                ArtistsUsed = new List<String>(ArtistsAdded);
                // ArtistsUsed = ArtistsAdded;
            }

            int ArtistCount = 0;
            if (NoDuplicates)
            {
                ArtistCount = ValidTracks.OfType<IITTrack>().Select(t => t.Artist).Distinct().Count();
            }
            else
            {
                ArtistCount = 10000;
            }

            int timeout = 0;
            for (int i = 0; i < ArtistCount && i < NumberOfSongs && ArtistsUsed.Count < ArtistCount && ValidTracks.Count > 0; )
            {
                if (timeout > 100)
                {
                    MessageBoxResult resu = MessageBox.Show("Quit at " + (SongsUsed.Count.ToString()) 
                        + "\nClick OK to Dismiss, Cancel for more info", "Something went Wrong", MessageBoxButton.OKCancel, MessageBoxImage.Exclamation, MessageBoxResult.OK);
                    if (resu == MessageBoxResult.Cancel)
                    {
                        MessageBox.Show("I tried 100 songs and didn't find any that could be added because\n\n" +
"a. the song already existed in this or a previous playlist (if you have 'refresh songs' selected) or\n " +
"b. the artist has already been added to this or a previous playlist (if you have 'refresh artists' selected).\n\n " +

"This probably means that all of your songs or artists have been used up, so I'm clearing the cache and you're " +
"going to have to start listening to the same music over again. 'HEY!' You say, 'I have a few more artist left,' etc. \n\n" +
"Well, the program works by choosing songs randomly, and when the count of songs/artists that have been used " +
"approaches the number of songs in your library, randomly selecting songs might take a while to find the few " +
"songs left that are valid additions, so I'm timing out at 100 failed tries.\n\n " +

"If you'd like to see this handled differently, shoot me an email at xander.dumaine@gmail.com", "How it works", MessageBoxButton.OK, MessageBoxImage.Information);

                    }
                    ArtistsUsed = new List<String>();
                    ArtistsAdded = new List<String>();
                    ValidTracks = Tracks;
                    e.Cancel = true;
                    return;
                }

                //check for cancelled flag.
                if (bcLoad.CancellationPending == true)
                {
                    e.Cancel = true;
                    return;
                }

                //get a random track
                IITTrack track;
                int random = 0;
                try
                {
                    random = rand.Next() % (ValidTracks.Count - 1);
                    track = ValidTracks[random];
                }
                catch (DivideByZeroException)
                {
                    random = 0;
                    track = ValidTracks[0];
                }

                //verify the file exists - if it does not, remove it and continue
                if (track.Kind == ITTrackKind.ITTrackKindFile)
                {
                    IITFileOrCDTrack fileTrack = (IITFileOrCDTrack)track;
                    //if the file doesn’t exist, we’ll delete it from iTunes           
                    if (fileTrack.Location == String.Empty || !System.IO.File.Exists(fileTrack.Location))
                    {
                        //fileTrack.Delete();
                        ValidTracks.RemoveAt(random);
                        timeout++;
                        continue;
                    }
                }

                if (track.Artist == null && (NoDuplicates || RefreshArtists || BlackOrWhiteList))
                {
                    ValidTracks.RemoveAt(random);
                    timeout++;
                    continue;
                }

                //if there are any artists blacklisted, check the current track against the blacklist
                if (BlacklistArtists != null && BlacklistArtists.Count > 0 && track.Artist != null)
                {
                    bool matchExists;
                    if (Substring)
                    {
                        matchExists = BlacklistArtists.Exists(delegate(string s) { return track.Artist.Trim().ToUpper().Contains(s.Trim().ToUpper()); });
                    }
                    else
                    {
                        matchExists = BlacklistArtists.Exists(delegate(string s) { return s == track.Artist.Trim().ToUpper(); });
                    }

                    //If the artist of the current song is in the BlackList AND the option is set to Blacklist                        
                    if (matchExists && !BlackOrWhiteList)
                    {
                        timeout++;
                        continue;
                    }
                    //If the artist of the current song is not in the Blacklist AND the option is set to Choose From
                    else if (!matchExists && BlackOrWhiteList)
                    {
                        timeout++;
                        continue;
                    }
                }

                //check if the track has already been added
                if (track.Artist != null && ArtistsUsed.Exists(delegate(string s) { return s == track.Artist.Trim().ToUpper(); }))
                {
                    timeout++;
                    continue;
                }

                //add the track to the playlist
                PlaylistBeingCreated.AddTrack(track);

        
        //Do this now when using ValidTracks
                //remove the track from ValidTracks
                ValidTracks.RemoveAt(random);

                //add the track to the property to update progress and show addition
                LocalSongsUsed.Add(track);
                SongsUsed = new List<IITTrack>(LocalSongsUsed);

                //add the artist name to the local list of artists to allow for "refresh" later
                if (track.Artist != null)
                {
                    ArtistsAdded.Add(track.Artist.Trim().ToUpper());
                }

                //if no duplicates is selected, add the artist name to the local list of artists to prevent readdition
                if (track.Artist != null && NoDuplicates)
                {
                    ArtistsUsed.Add(track.Artist.Trim().ToUpper());
                }

                //reset the timeout
                timeout = 0;
                i++;

            }



            if (SongsUsed.Count < NumberOfSongs)
            {
                MessageBoxResult resu = MessageBox.Show("Quit with " + (SongsUsed.Count.ToString())
                        + "\nClick OK to Dismiss, Cancel for more info", "Something went Wrong", MessageBoxButton.OKCancel, MessageBoxImage.Exclamation, MessageBoxResult.OK);
                if (resu == MessageBoxResult.Cancel)
                {
                    MessageBox.Show("I tried to add songs but couldn't because\n\n" +
"a. the song already existed in this or a previous playlist (if you have 'refresh songs' selected) or \n" +
"b. the artist has already been added to this or a previous playlist (if you have 'refresh artists' selected).\n\n " +

"This probably means that all of your songs or artists have been used up, so I'm clearing the cache and you're " +
"going to have to start listening to the same music over again. 'HEY!' You say, 'I have a few more artist left,' etc. \n\n" +
"Well, the program works by choosing songs randomly, and when the count of songs/artists that have been used " +
"approaches the number of songs in your library, randomly selecting songs might take a while to find the few " +
"songs left that are valid additions, so I'm timing out at 100 failed tries.\n\n " +

"If you'd like to see this handled differently, shoot me an email at xander.dumaine@gmail.com", "How it works", MessageBoxButton.OK, MessageBoxImage.Information);
                }
                ArtistsUsed = new List<String>();
                ArtistsAdded = new List<String>();
                ValidTracks = Tracks;
            }
        }

        /// <summary>
        /// Cleanup for the background worker playlist generation
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void bcLoad_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //System.Media.SystemSounds.Exclamation.Play();
            ArtistsUsed = new List<String>();
            LocalSongsUsed = new List<IITTrack>();
            ButtonMessage = "Done";
            
            //Resume the clock (timer) to check the current song, etc.
            Clock.Start();

            if (NumberOfSongs == 0)
            {
                Execute();
            }
        }

        /// <summary>
        /// Handle the Global "execute" button depending on its state
        /// </summary>
        public void Execute()
        {
            if(ButtonMessage == "Cancel")
            {
                bcLoad.CancelAsync();
                ButtonMessage = "Done";
            }
            else if (ButtonMessage == "Generate")
            {
                if (NumberOfSongs == 0)
                {
                    return;
                }
                bcLoad.RunWorkerAsync();
                ButtonMessage = "Cancel";
            }
            else if (ButtonMessage == "Done")
            {
                IsIdle = true;
                SongsUsed = new List<IITTrack>();
                ButtonMessage = "Generate";
            }
            else
            {
                bcLoad.CancelAsync();
                ButtonMessage = "Done";
            }
        }

        /// <summary>
        /// Takes a string name of a playlist to start the first track. If the playlist does not exist, the library is started.
        /// </summary>
        /// <param name="Playlist"></param>
        public void WakeUp(String Playlist)
        {
            try
            {
                iTunes.LibrarySource.Playlists.get_ItemByName(Playlist).PlayFirstTrack();
            }
            catch
            {
                iTunes.LibraryPlaylist.PlayFirstTrack();
            }
        }

        /// <summary>
        /// Turn iTunes into MiniPlayer
        /// </summary>
        public void MiniPlayer()
        {
            IITBrowserWindow win = (IITBrowserWindow)iTunes.Windows[1];
            win.MiniPlayer = true;
        }

        /// <summary>
        /// Event called on timer (Clock) - Checks the current song in iTunes, updates if appropriate
        /// Also Checks the PlayState, to ensure the player controls are in sync. 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Check_Song(object sender, ElapsedEventArgs e)
        {
            CheckSong();
        }

        /// <summary>
        /// Called from event called on timer (Clock) - Checks the current song in iTunes, updates if appropriate
        /// Also Checks the PlayState, to ensure the player controls are in sync. 
        /// </summary>
        public void CheckSong()
        {
            try
            {
                if (iTunes.CurrentTrack == null)
                {
                    CurrentSong = null;
                }
                else if (((IITTrack)CurrentSong) == null || ((IITTrack)CurrentSong).trackID != iTunes.CurrentTrack.trackID)
                {
                    CurrentSong = iTunes.CurrentTrack;
                }
                if (iTunes.CurrentTrack != null)
                {
                    TrackDuration = ((IITTrack)CurrentSong).Duration;
                    PlayerPosition = iTunes.PlayerPosition;
                    RaisePropertyChanged("PlayState");
                }
            }
            catch (Exception excep)
            {
                Console.WriteLine(excep.Message);
                //event log may not be best? it may need admin rights to work..
                //EventLog.WriteEntry("iPlay", "iTunes may be busy, unable to check current song");
            }
        }

        /// <summary>
        /// Not used - Consider removing
        /// </summary>
        public void Manipulated()
        {
            throw new NotImplementedException();
        }

        #endregion

    }
}
